import 'dart:math';

import 'package:flutter/material.dart';

class CirclePacking extends StatelessWidget {
  late double radius;

  CirclePacking({Key? key, this.radius = 10}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return SizedBox(
        width: radius * 2,
        height: radius * 2,
        child: CustomPaint(
          painter: CirclePackingPainter(radius),
        ));
  }
}

class CirclePackingPainter extends CustomPainter {
  late double radius;

  CirclePackingPainter(this.radius) : super();

  void _drawCircle(Canvas canvas) {
    Paint paint = Paint()
      ..strokeWidth = 1
      ..isAntiAlias = true
      ..style = PaintingStyle.stroke;

    paint.color = Color(0xFF3B5EFD);
    Offset offset = Offset(radius, radius);
    canvas.drawCircle(offset, radius, paint);
  }

  @override
  void paint(Canvas canvas, Size size) {
    _drawCircle(canvas);
  }

  @override
  bool shouldRepaint(CirclePackingPainter oldDelegate) => false;
}

class LinePacking extends StatelessWidget {
  late double width;
  late double height;

  LinePacking({Key? key, this.width = 20, this.height = 0}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ClipRect(
        child: SizedBox(
            width: width,
            height: height,
            child: CustomPaint(
              painter: LinePackingPainter(width,
                  height == 0 ? 3000 : height),
            )));
  }
}

class LinePackingPainter extends CustomPainter {
  late double width;
  late double height;

  LinePackingPainter(this.width, this.height) : super();

  void _drawLine(Canvas canvas) {
    Paint paint = Paint()
      ..strokeWidth = 1
      ..isAntiAlias = true
      ..style = PaintingStyle.stroke;

    paint.color = const Color(0xFF3B5EFD);
    Offset p1 = Offset(width / 2 - 0.5, 0);
    Offset p2 = Offset(width / 2, height);
    canvas.drawDashLine(p1, p2, 2, 2, paint);
  }

  @override
  void paint(Canvas canvas, Size size) {
    _drawLine(canvas);
  }

  @override
  bool shouldRepaint(LinePackingPainter oldDelegate) => false;
}

///
/// Canvas扩展函数
/// @Author weitianpeng
/// @Create 2021-3-28
///
extension CanvasExt on Canvas {
  ///绘制虚线
  ///[p1] 起点
  ///[p2] 终点
  ///[dashWidth] 实线宽度
  ///[spaceWidth] 空隙宽度
  void drawDashLine(
    Offset p1,
    Offset p2,
    double dashWidth,
    double spaceWidth,
    Paint paint,
  ) {
    assert(dashWidth > 0);
    assert(spaceWidth > 0);

    double radians;

    if (p1.dx == p2.dx) {
      radians = (p1.dy < p2.dy) ? pi / 2 : pi / -2;
    } else {
      radians = atan2(p2.dy - p1.dy, p2.dx - p1.dx);
    }

    this.save();
    this.translate(p1.dx, p1.dy);
    this.rotate(radians);

    var matrix = Matrix4.identity();
    matrix.translate(p1.dx, p1.dy);
    matrix.rotateZ(radians);
    matrix.invert();

    var endPoint = MatrixUtils.transformPoint(matrix, p2);

    double tmp = 0;
    double length = endPoint.dx;
    double delta;

    while (tmp < length) {
      delta = (tmp + dashWidth < length) ? dashWidth : length - tmp;
      this.drawLine(Offset(tmp, 0), Offset(tmp + delta, 0), paint);
      if (tmp + delta >= length) {
        break;
      }

      tmp = (tmp + dashWidth + spaceWidth < length)
          ? (tmp + dashWidth + spaceWidth)
          : (length);
    }

    this.restore();
  }

  ///绘制虚线
  ///[rect] 矩形
  ///[dashWidth] 实线宽度
  ///[spaceWidth] 空隙宽度
  void drawDashRect(
    Rect rect,
    double dashWidth,
    double spaceWidth,
    Paint paint,
  ) {
    drawDashLine(rect.topLeft, rect.topRight, dashWidth, spaceWidth, paint);
    drawDashLine(rect.topRight, rect.bottomRight, dashWidth, spaceWidth, paint);
    drawDashLine(
        rect.bottomRight, rect.bottomLeft, dashWidth, spaceWidth, paint);
    drawDashLine(rect.bottomLeft, rect.topLeft, dashWidth, spaceWidth, paint);
  }
}
